﻿#region Copyright (c) 2006-2011 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2011 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;

using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
using Widgetsphere.Generator.Common.Logging;

namespace Widgetsphere.VsCodeTools
{
	/// <summary>
	/// Factory for creating our editor object. Extends from the IVsEditoryFactory interface
	/// </summary>
	[Guid(GuidList.guidVsCodeToolsEditorFactoryString)]
	public sealed class EditorFactory : IVsEditorFactory, IDisposable
	{
		private VsCodeToolsPackage editorPackage;
		private ServiceProvider vsServiceProvider;

		public EditorFactory(VsCodeToolsPackage package)
		{
			WSLog.LogVerbose("Entering {0} constructor", this.ToString());
			this.editorPackage = package;
		}

		/// <summary>
		/// Since we create a ServiceProvider which implements IDisposable we
		/// also need to implement IDisposable to make sure that the ServiceProvider's
		/// Dispose method gets called.
		/// </summary>
		public void Dispose()
		{
			if (vsServiceProvider != null)
			{
				vsServiceProvider.Dispose();
			}
		}

		#region IVsEditorFactory Members

		public int SetSite(Microsoft.VisualStudio.OLE.Interop.IServiceProvider psp)
		{
			vsServiceProvider = new ServiceProvider(psp);
			return VSConstants.S_OK;
		}

		public object GetService(Type serviceType)
		{
			if (vsServiceProvider == null) return null;
			else return vsServiceProvider.GetService(serviceType);
		}

		// This method is called by the Environment (inside IVsUIShellOpenDocument::
		// OpenStandardEditor and OpenSpecificEditor) to map a LOGICAL view to a 
		// PHYSICAL view. A LOGICAL view identifies the purpose of the view that is
		// desired (e.g. a view appropriate for Debugging [LOGVIEWID_Debugging], or a 
		// view appropriate for text view manipulation as by navigating to a find
		// result [LOGVIEWID_TextView]). A PHYSICAL view identifies an actual type 
		// of view implementation that an IVsEditorFactory can create. 
		//
		// NOTE: Physical views are identified by a string of your choice with the 
		// one constraint that the default/primary physical view for an editor  
		// *MUST* use a NULL string as its physical view name (*pbstrPhysicalView = NULL).
		//
		// NOTE: It is essential that the implementation of MapLogicalView properly
		// validates that the LogicalView desired is actually supported by the editor.
		// If an unsupported LogicalView is requested then E_NOTIMPL must be returned.
		//
		// NOTE: The special Logical Views supported by an Editor Factory must also 
		// be registered in the local registry hive. LOGVIEWID_Primary is implicitly 
		// supported by all editor types and does not need to be registered.
		// For example, an editor that supports a ViewCode/ViewDesigner scenario
		// might register something like the following:
		//      HKLM\Software\Microsoft\VisualStudio\8.0\Editors\
		//          {...guidEditor...}\
		//              LogicalViews\
		//                  {...LOGVIEWID_TextView...} = s ''
		//                  {...LOGVIEWID_Code...} = s ''
		//                  {...LOGVIEWID_Debugging...} = s ''
		//                  {...LOGVIEWID_Designer...} = s 'Form'
		//
		public int MapLogicalView(ref Guid rguidLogicalView, out string pbstrPhysicalView)
		{
			pbstrPhysicalView = null;   // initialize out parameter

			// we support only a single physical view
			if (VSConstants.LOGVIEWID_Primary == rguidLogicalView)
				return VSConstants.S_OK;        // primary view uses NULL as pbstrPhysicalView
			else
				return VSConstants.E_NOTIMPL;   // you must return E_NOTIMPL for any unrecognized rguidLogicalView values
		}

		public int Close()
		{
			return VSConstants.S_OK;
		}

		public int CreateEditorInstance(
										uint grfCreateDoc,
										string pszMkDocument,
										string pszPhysicalView,
										IVsHierarchy pvHier,
										uint itemid,
										System.IntPtr punkDocDataExisting,
										out System.IntPtr ppunkDocView,
										out System.IntPtr ppunkDocData,
										out string pbstrEditorCaption,
										out Guid pguidCmdUI,
										out int pgrfCDW)
		{
			WSLog.LogVerbose("Entering {0} CreateEditorInstance()", this.ToString());

			// Initialize to null
			ppunkDocView = IntPtr.Zero;
			ppunkDocData = IntPtr.Zero;
			pguidCmdUI = GuidList.guidVsCodeToolsEditorFactory;
			pgrfCDW = 0;
			pbstrEditorCaption = null;

			// Validate inputs
			if ((grfCreateDoc & (VSConstants.CEF_OPENFILE | VSConstants.CEF_SILENT)) == 0)
			{
				Debug.Assert(false, "Only Open or Silent is valid");
				return VSConstants.E_INVALIDARG;
			}
			if (punkDocDataExisting != IntPtr.Zero)
			{
				return VSConstants.VS_E_INCOMPATIBLEDOCDATA;
			}

			// Create the Document (editor)
			var newEditor = new ModelViewer(editorPackage);
			//var newEditor = new EditorPane(editorPackage); 
			ppunkDocView = Marshal.GetIUnknownForObject(newEditor);
			ppunkDocData = Marshal.GetIUnknownForObject(newEditor);
			pbstrEditorCaption = string.Empty;
			return VSConstants.S_OK;
		}

		#endregion

	}
}